Proper connect_port
[juce-lv2.git] / juce / source / extras / browser plugins / wrapper / juce_NPAPI_GlueCode.cpp
blob316e2086562e7528ef079bd32fa64b32b0f27e51
1 /*
2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 //==============================================================================
28 This file contains all the mess that creates an NPAPI interface, and connects
29 that interface to your BrowserPluginComponent object.
32 //==============================================================================
33 #if defined (__APPLE__) && ! JUCE_NPAPI_WRAPPED_IN_MM
34 #error "On the Mac, you can't compile this .cpp file directly - use juce_NPAPI_GlueCode.mm instead"
35 #endif
37 #define XPCOM_GLUE
39 //==============================================================================
40 #if _MSC_VER
41 #define XP_WIN
42 #define _X86_
43 #include <windows.h>
44 #include <windowsx.h>
45 #include "npapi/npupp.h"
47 // Cunning trick used to add functions to export list and avoid messing about with .def files.
48 // (can't add a declspec because the functions have already been pre-declared in the npapi headers).
49 #define EXPORTED_FUNCTION comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__)
51 //==============================================================================
52 #elif defined (__APPLE__)
53 #define XP_MACOSX
54 #define OSCALL
55 #include <WebKit/npapi.h>
56 #include <WebKit/npfunctions.h>
57 #include <WebKit/npruntime.h>
59 //==============================================================================
60 #else
61 #define XP_UNIX
62 #include "npapi.h"
63 #include "npupp.h"
64 #include "npruntime.h"
66 #endif
68 //==============================================================================
69 #include "juce_IncludeBrowserPluginInfo.h"
70 #include "../../../juce_amalgamated.h"
71 #include "juce_BrowserPluginComponent.h"
73 #if JUCE_MAC && JUCE_DEBUG && 0
74 #include <fstream>
75 static void log (const String& s)
77 std::ofstream file ("/Users/jules/Desktop/log.txt", std::ios::out | std::ios::app);
78 file << s << std::endl;
80 #else
81 #define log(a)
82 #endif
84 //==============================================================================
85 #if JUCE_MAC
86 static const String nsStringToJuce (NSString* s) { return String::fromUTF8 ([s UTF8String]); }
87 static NSString* juceStringToNS (const String& s) { return [NSString stringWithUTF8String: s.toUTF8()]; }
89 #pragma export on
90 extern "C"
92 NPError NP_Initialize (NPNetscapeFuncs*);
93 NPError NP_GetEntryPoints (NPPluginFuncs*);
94 NPError NP_Shutdown();
96 #pragma export off
98 #ifndef NP_CLASS_STRUCT_VERSION_ENUM // fill in some symbols that are missing from the OSX 10.4 SDK
99 #define NPNVpluginDrawingModel 1000
100 #define NPDrawingModelCoreGraphics 1
102 typedef struct NP_CGContext
104 CGContextRef context;
105 WindowRef window;
106 } NP_CGContext;
107 #endif
109 #endif
111 //==============================================================================
112 static NPNetscapeFuncs browser;
113 String browserVersionDesc;
115 //==============================================================================
116 NPError NP_GetValue (void* future, NPPVariable variable, void* value)
118 return NPP_GetValue ((NPP_t*) future, variable, value);
121 #if JUCE_WINDOWS || JUCE_MAC
122 NPError OSCALL NP_GetEntryPoints (NPPluginFuncs* funcs)
124 #if JUCE_WINDOWS
125 #pragma EXPORTED_FUNCTION
126 #endif
128 log ("NP_GetEntryPoints");
129 if (funcs == 0 || (funcs->size > 0 && funcs->size < sizeof (NPPluginFuncs)))
130 return NPERR_INVALID_FUNCTABLE_ERROR;
132 funcs->size = sizeof (NPPluginFuncs);
133 funcs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
134 funcs->newp = NPP_New;
135 funcs->destroy = NPP_Destroy;
136 funcs->setwindow = NPP_SetWindow;
137 funcs->newstream = NPP_NewStream;
138 funcs->destroystream = NPP_DestroyStream;
139 funcs->asfile = NPP_StreamAsFile;
140 funcs->writeready = NPP_WriteReady;
141 #if JUCE_MAC
142 funcs->write = (NPP_WriteProcPtr) NPP_Write;
143 #else
144 funcs->write = NPP_Write;
145 #endif
146 funcs->print = NPP_Print;
147 funcs->event = NPP_HandleEvent;
148 funcs->urlnotify = NPP_URLNotify;
149 funcs->getvalue = NPP_GetValue;
150 funcs->setvalue = NPP_SetValue;
151 funcs->javaClass = nullptr;
153 return NPERR_NO_ERROR;
155 #endif
157 NPError OSCALL NP_Initialize (NPNetscapeFuncs* funcs
158 #ifdef XP_UNIX
159 , NPPluginFuncs* pluginFuncs
160 #endif
163 #if JUCE_WINDOWS
164 #pragma EXPORTED_FUNCTION
165 #endif
167 log ("NP_Initialize");
168 if (funcs == 0)
169 return NPERR_INVALID_FUNCTABLE_ERROR;
171 if (((funcs->version >> 8) & 0xff) > NP_VERSION_MAJOR)
172 return NPERR_INCOMPATIBLE_VERSION_ERROR;
174 zerostruct (browser);
175 memcpy (&browser, funcs, jmin ((size_t) funcs->size, sizeof (browser)));
177 #ifdef XP_UNIX
178 pluginFuncs->version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
179 pluginFuncs->size = sizeof (NPPluginFuncs);
180 pluginFuncs->newp = NewNPP_NewProc (NPP_New);
181 pluginFuncs->destroy = NewNPP_DestroyProc (NPP_Destroy);
182 pluginFuncs->setwindow = NewNPP_SetWindowProc (NPP_SetWindow);
183 pluginFuncs->newstream = NewNPP_NewStreamProc (NPP_NewStream);
184 pluginFuncs->destroystream = NewNPP_DestroyStreamProc (NPP_DestroyStream);
185 pluginFuncs->asfile = NewNPP_StreamAsFileProc (NPP_StreamAsFile);
186 pluginFuncs->writeready = NewNPP_WriteReadyProc (NPP_WriteReady);
187 pluginFuncs->write = NewNPP_WriteProc (NPP_Write);
188 pluginFuncs->print = NewNPP_PrintProc (NPP_Print);
189 pluginFuncs->urlnotify = NewNPP_URLNotifyProc (NPP_URLNotify);
190 pluginFuncs->event = 0;
191 pluginFuncs->getvalue = NewNPP_GetValueProc (NPP_GetValue);
192 #ifdef OJI
193 pluginFuncs->javaClass = NPP_GetJavaClass();
194 #endif
195 #endif
197 return NPERR_NO_ERROR;
200 NPError OSCALL NP_Shutdown()
202 #if JUCE_WINDOWS
203 #pragma EXPORTED_FUNCTION
204 #endif
206 log ("NP_Shutdown");
207 return NPERR_NO_ERROR;
210 char* NP_GetMIMEDescription()
212 log ("NP_GetMIMEDescription");
213 static String mimeDesc;
215 mimeDesc = String (T(JuceBrowserPlugin_MimeType))
216 + ":" + String (T(JuceBrowserPlugin_FileSuffix))
217 + ":" + String (T(JuceBrowserPlugin_Name));
219 return (char*) (const char*) mimeDesc.toUTF8();
222 //==============================================================================
224 NPError NPN_GetURLNotify (NPP instance, const char *url, const char *target, void* notifyData)
226 return (browser.version & 0xFF) >= NPVERS_HAS_NOTIFICATION
227 ? browser.geturlnotify (instance, url, target, notifyData);
228 : NPERR_INCOMPATIBLE_VERSION_ERROR;
231 NPError NPN_PostURLNotify (NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file, void* notifyData)
233 return (browser.version & 0xFF) >= NPVERS_HAS_NOTIFICATION
234 ? browser.posturlnotify (instance, url, window, len, buf, file, notifyData)
235 : NPERR_INCOMPATIBLE_VERSION_ERROR;
238 NPError NPN_NewStream (NPP instance, NPMIMEType type, const char* target, NPStream** stream)
240 return (browser.version & 0xFF) >= NPVERS_HAS_STREAMOUTPUT
241 ? browser.newstream (instance, type, target, stream)
242 : NPERR_INCOMPATIBLE_VERSION_ERROR;
245 int32 NPN_Write (NPP instance, NPStream *stream, int32 len, void *buffer)
247 return (browser.version & 0xFF) >= NPVERS_HAS_STREAMOUTPUT
248 ? browser.write (instance, stream, len, buffer)
249 : -1;
252 NPError NPN_DestroyStream (NPP instance, NPStream* stream, NPError reason)
254 return (browser.version & 0xFF) >= NPVERS_HAS_STREAMOUTPUT
255 ? browser.destroystream (instance, stream, reason)
256 : NPERR_INCOMPATIBLE_VERSION_ERROR;
260 //==============================================================================
261 class BrowserPluginHolderComponent : public Component
263 public:
264 //==============================================================================
265 BrowserPluginHolderComponent (NPP npp_)
266 : npp (npp_)
268 log ("BrowserPluginHolderComponent created");
269 #if JUCE_WINDOWS
270 parentHWND = 0;
271 oldWinProc = 0;
272 #else
273 currentParentView = 0;
274 #endif
276 setOpaque (true);
277 setWantsKeyboardFocus (false);
279 addAndMakeVisible (child = createBrowserPlugin());
280 jassert (child != nullptr); // You have to create one of these!
283 ~BrowserPluginHolderComponent()
285 log ("BrowserPluginHolderComponent deleted");
286 setWindow (nullptr);
287 child = nullptr;
290 //==============================================================================
291 void paint (Graphics& g)
293 if (child == nullptr || ! child->isOpaque())
294 g.fillAll (Colours::white);
297 void resized()
299 if (child != nullptr)
300 child->setBounds (getLocalBounds());
303 const var getObject()
305 return child->getJavascriptObject();
308 //==============================================================================
309 NPP npp;
310 ScopedPointer<BrowserPluginComponent> child;
312 private:
314 //==============================================================================
315 #if JUCE_WINDOWS
316 HWND parentHWND;
317 WNDPROC oldWinProc;
319 void resizeToParentWindow (const int requestedWidth = 0, const int requestedHeight = 0)
321 if (IsWindow (parentHWND))
323 RECT r;
324 GetWindowRect (parentHWND, &r);
326 int w = r.right - r.left;
327 int h = r.bottom - r.top;
329 if (w == 0 || h == 0)
331 w = requestedWidth; // On Safari, the HWND can have a zero-size, so we might need to
332 h = requestedHeight; // force it to the size that the NPAPI call asked for..
333 MoveWindow (parentHWND, r.left, r.top, w, h, TRUE);
336 setBounds (0, 0, w, h);
340 static LRESULT CALLBACK interceptingWinProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
342 switch (msg)
344 case WM_PAINT:
346 PAINTSTRUCT ps;
347 HDC hdc = BeginPaint (hWnd, &ps);
348 EndPaint (hWnd, &ps);
350 return 0;
352 case WM_ERASEBKGND:
353 return 1;
355 case WM_WINDOWPOSCHANGING:
356 case WM_WINDOWPOSCHANGED:
357 //if ((((WINDOWPOS*) lParam)->flags & SWP_NOSIZE) == 0)
359 BrowserPluginHolderComponent* const comp = (BrowserPluginHolderComponent*) GetWindowLongPtr (hWnd, GWLP_USERDATA);
360 comp->resizeToParentWindow();
362 break;
364 default:
365 break;
368 return DefWindowProc (hWnd, msg, wParam, lParam);
371 public:
372 void setWindow (NPWindow* window)
374 HWND newHWND = (window != nullptr ? ((HWND) window->window) : 0);
376 if (parentHWND != newHWND)
378 removeFromDesktop();
379 setVisible (false);
381 if (IsWindow (parentHWND))
383 SubclassWindow (parentHWND, oldWinProc); // restore the old winproc..
384 oldWinProc = 0;
387 parentHWND = newHWND;
389 if (parentHWND != 0)
391 addToDesktop (0, parentHWND);
392 setVisible (true);
394 oldWinProc = SubclassWindow (parentHWND, (WNDPROC) interceptingWinProc);
396 jassert (GetWindowLongPtr (parentHWND, GWLP_USERDATA) == 0);
397 SetWindowLongPtr (parentHWND, GWLP_USERDATA, (LONG_PTR) this);
399 resizeToParentWindow (window->width, window->height);
404 //==============================================================================
405 #else
406 NSView* currentParentView;
408 NSView* findViewAt (NSView* parent, float x, float y) const
410 NSRect frame = [parent frame];
411 NSRect bounds = [parent bounds];
412 x -= frame.origin.x;
413 y -= frame.origin.y;
415 Rectangle<int> rr (frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
416 Rectangle<int> rr2 (bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
417 //log (String ((int) x) + ", " + String ((int) y) + " - " + nsStringToJuce([parent description]) + " " + rr.toString() + " " + rr2.toString());
419 if (x >= 0 && x < frame.size.width && y >= 0 && y < frame.size.height)
421 x += bounds.origin.x; // adjust for scrolling panels
422 y += bounds.origin.y;
424 for (int i = [[parent subviews] count]; --i >= 0;)
426 NSView* v = (NSView*) [[parent subviews] objectAtIndex: i];
428 if (v != (NSView*) getWindowHandle() && ! [v isHidden])
430 NSView* found = findViewAt (v, x, y);
432 if (found != nil)
433 return found;
437 if (isBrowserContentView (parent))
438 return parent;
441 return nil;
444 public:
445 static bool isBrowserContentView (NSView* v)
447 return [[v className] isEqualToString: @"WebNetscapePluginDocumentView"]
448 || [[v className] isEqualToString: @"WebPluginDocumentView"]
449 || ([[v className] isEqualToString: @"ChildView"] && ([v frame].origin.x != 0 && [v frame].origin.y != 0));
452 void setWindow (NPWindow* window)
454 const ScopedAutoReleasePool pool;
456 log ("setWindow");
458 NSView* parentView = nil;
459 NP_CGContext* const cgContext = (window != nullptr) ? (NP_CGContext*) window->window : nullptr;
460 log ("NP_CGContext: " + String::toHexString ((pointer_sized_int) cgContext));
462 #ifndef __LP64__
463 WindowRef windowRef = cgContext != nullptr ? (WindowRef) cgContext->window : 0;
465 if (windowRef != 0)
467 NSWindow* win = [[[NSWindow alloc] initWithWindowRef: windowRef] autorelease];
468 #else
469 NSWindow* win = cgContext != nullptr ? (NSWindow*) cgContext->window : nil;
471 if (win != nil)
473 #endif
474 log ("window: " + nsStringToJuce ([win description]));
476 const Rectangle<int> clip (window->clipRect.left, window->clipRect.top,
477 window->clipRect.right - window->clipRect.left,
478 window->clipRect.bottom - window->clipRect.top);
479 const Rectangle<int> target ((int) window->x, (int) window->y, (int) window->width, (int) window->height);
480 const Rectangle<int> intersection (clip.getIntersection (target));
482 // in firefox the clip rect is usually out of step with the target rect, but in safari it matches
483 log ("plugin window clip: " + clip.toString());
484 log ("plugin window target: " + target.toString());
485 log ("plugin window intersection: " + intersection.toString());
487 if (! intersection.isEmpty())
489 NSView* content = [win contentView];
490 log ("content: " + nsStringToJuce ([content description]));
492 float wx = (float) intersection.getCentreX();
493 float wy = (float) intersection.getCentreY();
495 NSRect v = [content convertRect: [content frame] toView: nil];
496 NSRect w = [win frame];
498 log ("wx: " + Rectangle<int> (v.origin.x, v.origin.y, v.size.width, v.size.height).toString()
499 + " " + Rectangle<int> (w.origin.x, w.origin.y, w.size.width, w.size.height).toString());
501 // adjust the requested window pos to deal with the content view's origin within the window
502 wy -= w.size.height - (v.origin.y + v.size.height);
504 parentView = findViewAt (content, wx, wy);
506 if (! isBrowserContentView (parentView))
507 parentView = currentParentView;
509 else if (currentParentView != nil && ! target.isEmpty())
511 // Firefox can send lots of spurious resize messages when updating its pages, so this is a
512 // bodge to avoid flickering caused by repeatedly removing and re-adding the view..
513 parentView = currentParentView;
516 log ("parent: " + nsStringToJuce ([parentView description]));
519 if (parentView != currentParentView)
521 log ("new view: " + nsStringToJuce ([parentView description]));
523 removeFromDesktop();
524 setVisible (false);
526 currentParentView = parentView;
528 if (parentView != nil)
530 setSize (window->width, window->height);
531 addToDesktop (0, parentView);
532 setVisible (true);
536 if (window != nullptr)
537 setSize (window->width, window->height);
539 #endif
542 //==============================================================================
543 static NPIdentifier getIdentifierFromString (const var::identifier& s) noexcept
545 return browser.getstringidentifier (s.toString().toUTF8());
548 static const var createValueFromNPVariant (NPP npp, const NPVariant& v);
549 static void createNPVariantFromValue (NPP npp, NPVariant& out, const var& v);
551 #if JUCE_DEBUG
552 static int numDOWNP = 0, numJuceSO = 0;
553 #endif
555 //==============================================================================
556 class DynamicObjectWrappingNPObject : public DynamicObject
558 NPP npp;
559 NPObject* const source;
561 public:
562 DynamicObjectWrappingNPObject (NPP npp_, NPObject* const source_)
563 : npp (npp_),
564 source (browser.retainobject (source_))
566 DBG ("num NP wrapper objs: " + String (++numDOWNP));
569 ~DynamicObjectWrappingNPObject()
571 browser.releaseobject (source);
572 DBG ("num NP wrapper objs: " + String (--numDOWNP));
575 var getProperty (const var::identifier& propertyName) const
577 NPVariant result;
578 VOID_TO_NPVARIANT (result);
579 browser.getproperty (npp, source, getIdentifierFromString (propertyName), &result);
580 const var v (createValueFromNPVariant (npp, result));
581 browser.releasevariantvalue (&result);
582 return v;
585 bool hasProperty (const var::identifier& propertyName) const
587 NPVariant result;
588 VOID_TO_NPVARIANT (result);
589 const bool hasProp = browser.getproperty (npp, source, getIdentifierFromString (propertyName), &result);
590 browser.releasevariantvalue (&result);
591 return hasProp;
594 void setProperty (const var::identifier& propertyName, const var& newValue)
596 NPVariant value;
597 createNPVariantFromValue (npp, value, newValue);
599 browser.setproperty (npp, source, getIdentifierFromString (propertyName), &value);
600 browser.releasevariantvalue (&value);
603 void removeProperty (const var::identifier& propertyName)
605 browser.removeproperty (npp, source, getIdentifierFromString (propertyName));
608 bool hasMethod (const var::identifier& methodName) const
610 return browser.hasmethod (npp, source, getIdentifierFromString (methodName));
613 var invokeMethod (const var::identifier& methodName,
614 const var* parameters,
615 int numParameters)
617 var returnVal;
619 NPVariant result;
620 VOID_TO_NPVARIANT (result);
622 if (numParameters > 0)
624 HeapBlock <NPVariant> params (numParameters);
626 int i;
627 for (i = 0; i < numParameters; ++i)
628 createNPVariantFromValue (npp, params[i], parameters[i]);
630 if (browser.invoke (npp, source, getIdentifierFromString (methodName),
631 params, numParameters, &result))
633 returnVal = createValueFromNPVariant (npp, result);
634 browser.releasevariantvalue (&result);
637 for (i = 0; i < numParameters; ++i)
638 browser.releasevariantvalue (&params[i]);
640 else
642 if (browser.invoke (npp, source, getIdentifierFromString (methodName), 0, 0, &result))
644 returnVal = createValueFromNPVariant (npp, result);
645 browser.releasevariantvalue (&result);
649 return returnVal;
653 //==============================================================================
654 class NPObjectWrappingDynamicObject : public NPObject
656 public:
657 static NPObject* create (NPP npp, const var& objectToWrap);
659 virtual ~NPObjectWrappingDynamicObject()
661 DBG ("num Juce wrapper objs: " + String (--numJuceSO));
664 private:
665 NPObjectWrappingDynamicObject (NPP npp_)
666 : npp (npp_)
668 DBG ("num Juce wrapper objs: " + String (++numJuceSO));
671 //==============================================================================
672 bool construct (const NPVariant *args, uint32_t argCount, NPVariant *result);
673 void invalidate() {}
675 bool hasMethod (NPIdentifier name)
677 DynamicObject* const o = object.getDynamicObject();
678 return o != nullptr && o->hasMethod (identifierToString (name));
681 bool invoke (NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* out)
683 DynamicObject* const o = object.getDynamicObject();
684 const var::identifier methodName (identifierToString (name));
686 if (o == nullptr || ! o->hasMethod (methodName))
687 return false;
689 struct ParamHolder
691 ParamHolder (uint32_t num) { params = new var [num]; }
692 ~ParamHolder() { delete[] params; }
694 var* params;
697 ParamHolder params (argCount);
699 for (uint32_t i = 0; i < argCount; ++i)
700 params.params[i] = createValueFromNPVariant (npp, args[i]);
702 const var result (o->invokeMethod (methodName, params.params, argCount));
704 if (out != nullptr)
705 createNPVariantFromValue (npp, *out, result);
707 return true;
710 bool invokeDefault (const NPVariant* args, uint32_t argCount, NPVariant* result)
712 return false;
715 bool hasProperty (NPIdentifier name)
717 DynamicObject* const o = object.getDynamicObject();
718 return o != nullptr && o->hasProperty (identifierToString (name));
721 bool getProperty (NPIdentifier name, NPVariant* out)
723 DynamicObject* const o = object.getDynamicObject();
724 const var::identifier propName (identifierToString (name));
726 if (o == nullptr || ! o->hasProperty (propName))
727 return false;
729 const var result (o->getProperty (propName));
731 if (out != nullptr)
732 createNPVariantFromValue (npp, *out, result);
734 return true;
737 bool setProperty (NPIdentifier name, const NPVariant* value)
739 DynamicObject* const o = object.getDynamicObject();
741 if (value == nullptr || o == nullptr)
742 return false;
744 o->setProperty (identifierToString (name), createValueFromNPVariant (npp, *value));
745 return true;
748 bool removeProperty (NPIdentifier name)
750 DynamicObject* const o = object.getDynamicObject();
751 const var::identifier propName (identifierToString (name));
753 if (o == nullptr || ! o->hasProperty (propName))
754 return false;
756 o->removeProperty (propName);
757 return true;
760 bool enumerate (NPIdentifier** identifier, uint32_t* count)
762 return false;
765 //==============================================================================
766 NPP npp;
767 var object;
769 static const var::identifier identifierToString (NPIdentifier id)
771 NPUTF8* const name = browser.utf8fromidentifier (id);
772 const var::identifier result ((const char*) name);
773 browser.memfree (name);
774 return result;
777 public:
778 //==============================================================================
779 static NPObject* createInstance (NPP npp, NPClass* aClass) { return new NPObjectWrappingDynamicObject (npp); }
780 static void class_deallocate (NPObject* npobj) { delete (NPObjectWrappingDynamicObject*) npobj; }
781 static void class_invalidate (NPObject* npobj) { ((NPObjectWrappingDynamicObject*) npobj)->invalidate(); }
782 static bool class_hasMethod (NPObject* npobj, NPIdentifier name) { return ((NPObjectWrappingDynamicObject*) npobj)->hasMethod (name); }
783 static bool class_invoke (NPObject* npobj, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result) { return ((NPObjectWrappingDynamicObject*) npobj)->invoke (name, args, argCount, result); }
784 static bool class_invokeDefault (NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result) { return ((NPObjectWrappingDynamicObject*) npobj)->invokeDefault (args, argCount, result); }
785 static bool class_hasProperty (NPObject* npobj, NPIdentifier name) { return ((NPObjectWrappingDynamicObject*) npobj)->hasProperty (name); }
786 static bool class_getProperty (NPObject* npobj, NPIdentifier name, NPVariant* result) { return ((NPObjectWrappingDynamicObject*) npobj)->getProperty (name, result); }
787 static bool class_setProperty (NPObject* npobj, NPIdentifier name, const NPVariant* value) { return ((NPObjectWrappingDynamicObject*) npobj)->setProperty (name, value); }
788 static bool class_removeProperty (NPObject* npobj, NPIdentifier name) { return ((NPObjectWrappingDynamicObject*) npobj)->removeProperty (name); }
789 static bool class_enumerate (NPObject* npobj, NPIdentifier** identifier, uint32_t* count) { return ((NPObjectWrappingDynamicObject*) npobj)->enumerate (identifier, count); }
790 static bool class_construct (NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result) { return ((NPObjectWrappingDynamicObject*) npobj)->construct (args, argCount, result); }
793 static NPClass sNPObjectWrappingDynamicObject_NPClass =
795 #ifndef NP_CLASS_STRUCT_VERSION_ENUM
796 NP_CLASS_STRUCT_VERSION, NPObjectWrappingDynamicObject::createInstance,
797 NPObjectWrappingDynamicObject::class_deallocate, NPObjectWrappingDynamicObject::class_invalidate,
798 NPObjectWrappingDynamicObject::class_hasMethod, NPObjectWrappingDynamicObject::class_invoke,
799 NPObjectWrappingDynamicObject::class_invokeDefault, NPObjectWrappingDynamicObject::class_hasProperty,
800 NPObjectWrappingDynamicObject::class_getProperty, NPObjectWrappingDynamicObject::class_setProperty,
801 NPObjectWrappingDynamicObject::class_removeProperty
802 #else
803 NP_CLASS_STRUCT_VERSION_ENUM, NPObjectWrappingDynamicObject::createInstance,
804 NPObjectWrappingDynamicObject::class_deallocate, NPObjectWrappingDynamicObject::class_invalidate,
805 NPObjectWrappingDynamicObject::class_hasMethod, NPObjectWrappingDynamicObject::class_invoke,
806 NPObjectWrappingDynamicObject::class_invokeDefault, NPObjectWrappingDynamicObject::class_hasProperty,
807 NPObjectWrappingDynamicObject::class_getProperty, NPObjectWrappingDynamicObject::class_setProperty,
808 NPObjectWrappingDynamicObject::class_removeProperty, NPObjectWrappingDynamicObject::class_enumerate
809 #endif
812 bool NPObjectWrappingDynamicObject::construct (const NPVariant* args, uint32_t argCount, NPVariant* result)
814 NPObject* const newObj = browser.createobject (npp, &sNPObjectWrappingDynamicObject_NPClass);
816 if (newObj == nullptr)
817 return false;
819 OBJECT_TO_NPVARIANT (newObj, *result);
820 return true;
823 NPObject* NPObjectWrappingDynamicObject::create (NPP npp, const var& objectToWrap)
825 jassert (objectToWrap.getDynamicObject() != nullptr);
827 NPObject* const nppObject = browser.createobject (npp, &sNPObjectWrappingDynamicObject_NPClass);
829 if (nppObject != nullptr)
830 ((NPObjectWrappingDynamicObject*) nppObject)->object = objectToWrap;
832 return nppObject;
836 //==============================================================================
837 static const var createValueFromNPVariant (NPP npp, const NPVariant& v)
839 if (NPVARIANT_IS_BOOLEAN (v))
840 return var (NPVARIANT_TO_BOOLEAN (v));
841 else if (NPVARIANT_IS_INT32 (v))
842 return var (NPVARIANT_TO_INT32 (v));
843 else if (NPVARIANT_IS_DOUBLE (v))
844 return var (NPVARIANT_TO_DOUBLE (v));
845 else if (NPVARIANT_IS_STRING (v))
847 return var (String::fromUTF8 ((const char*)
848 #if JUCE_MAC
849 (NPVARIANT_TO_STRING (v).UTF8Characters), (int) NPVARIANT_TO_STRING (v).UTF8Length));
850 #else
851 (NPVARIANT_TO_STRING (v).utf8characters), (int) NPVARIANT_TO_STRING (v).utf8length));
852 #endif
854 else if (NPVARIANT_IS_OBJECT (v) && npp != nullptr)
855 return var (new DynamicObjectWrappingNPObject (npp, NPVARIANT_TO_OBJECT (v)));
857 return var::null;
860 static void createNPVariantFromValue (NPP npp, NPVariant& out, const var& v)
862 if (v.isInt())
863 INT32_TO_NPVARIANT ((int) v, out);
864 else if (v.isBool())
865 BOOLEAN_TO_NPVARIANT ((bool) v, out);
866 else if (v.isDouble())
867 DOUBLE_TO_NPVARIANT ((double) v, out);
868 else if (v.isString())
870 const String s (v.toString());
871 const char* const utf8 = s.toUTF8();
872 const int utf8Len = strlen (utf8) + 1;
873 char* const stringCopy = (char*) browser.memalloc (utf8Len);
874 memcpy (stringCopy, utf8, utf8Len);
875 STRINGZ_TO_NPVARIANT (stringCopy, out);
877 else if (v.getDynamicObject() != nullptr && npp != nullptr)
878 OBJECT_TO_NPVARIANT (NPObjectWrappingDynamicObject::create (npp, v), out);
879 else
880 VOID_TO_NPVARIANT (out);
883 //==============================================================================
884 class JucePluginInstance
886 public:
887 //==============================================================================
888 JucePluginInstance (NPP npp_)
889 : npp (npp_),
890 holderComp (nullptr),
891 scriptObject (nullptr)
895 ~JucePluginInstance()
897 setWindow (nullptr);
900 bool setWindow (NPWindow* window)
902 if (window != nullptr)
904 if (holderComp == nullptr)
905 holderComp = new BrowserPluginHolderComponent (npp);
907 holderComp->setWindow (window);
909 else
911 deleteAndZero (holderComp);
912 scriptObject = nullptr;
915 return true;
918 NPObject* getScriptableObject()
920 if (scriptObject == nullptr)
921 scriptObject = NPObjectWrappingDynamicObject::create (npp, holderComp->getObject());
923 if (scriptObject != nullptr && shouldRetainBrowserObject())
924 browser.retainobject (scriptObject);
926 return scriptObject;
929 //==============================================================================
930 NPP npp;
931 BrowserPluginHolderComponent* holderComp;
932 NPObject* scriptObject;
934 private:
935 bool shouldRetainBrowserObject() const
937 const String version (browser.uagent (npp));
939 if (! version.containsIgnoreCase (" AppleWebKit/"))
940 return true;
942 int versionNum = version.fromFirstOccurrenceOf (" AppleWebKit/", false, true).getIntValue();
944 return versionNum == 0 || versionNum >= 420;
948 //==============================================================================
949 static NPP currentlyInitialisingNPP = nullptr;
950 static int numPluginInstances = 0;
952 NPError NPP_New (NPMIMEType pluginType, NPP npp, ::uint16 mode, ::int16 argc, char* argn[], char* argv[], NPSavedData* saved)
954 log ("NPP_New");
955 if (npp == nullptr)
956 return NPERR_INVALID_INSTANCE_ERROR;
958 #if JUCE_MAC
959 browser.setvalue (npp, (NPPVariable) NPNVpluginDrawingModel, (void*) NPDrawingModelCoreGraphics);
961 #ifdef __LP64__
962 browser.setvalue (npp, (NPPVariable) 1001 /*NPPVpluginEventModel*/, (void*) 1 /*NPEventModelCocoa*/);
963 #else
964 browser.setvalue (npp, (NPPVariable) 1001 /*NPPVpluginEventModel*/, 0 /*NPEventModelCarbon*/);
965 #endif
966 #endif
968 if (numPluginInstances++ == 0)
970 log ("initialiseJuce_GUI()");
971 initialiseJuce_GUI();
974 currentlyInitialisingNPP = npp;
975 JucePluginInstance* p = new JucePluginInstance (npp);
976 currentlyInitialisingNPP = nullptr;
978 npp->pdata = (void*) p;
979 return NPERR_NO_ERROR;
982 NPError NPP_Destroy (NPP npp, NPSavedData** save)
984 log ("NPP_Destroy");
985 if (npp == nullptr)
986 return NPERR_INVALID_INSTANCE_ERROR;
988 JucePluginInstance* const p = (JucePluginInstance*) npp->pdata;
990 if (p != nullptr)
992 delete p;
994 if (--numPluginInstances == 0)
996 log ("shutdownJuce_GUI()");
997 shutdownJuce_GUI();
998 browserVersionDesc = String::empty;
1002 return NPERR_NO_ERROR;
1005 NPError NPP_SetWindow (NPP npp, NPWindow* pNPWindow)
1007 if (npp == nullptr)
1008 return NPERR_INVALID_INSTANCE_ERROR;
1010 if (pNPWindow == nullptr)
1011 return NPERR_GENERIC_ERROR;
1013 JucePluginInstance* const p = (JucePluginInstance*) npp->pdata;
1015 if (p == nullptr)
1016 return NPERR_GENERIC_ERROR;
1018 currentlyInitialisingNPP = npp;
1019 NPError result = p->setWindow (pNPWindow) ? NPERR_NO_ERROR
1020 : NPERR_MODULE_LOAD_FAILED_ERROR;
1021 currentlyInitialisingNPP = nullptr;
1022 return result;
1025 //==============================================================================
1026 NPError NPP_GetValue (NPP npp, NPPVariable variable, void* value)
1028 if (npp == nullptr)
1029 return NPERR_INVALID_INSTANCE_ERROR;
1031 JucePluginInstance* const p = (JucePluginInstance*) npp->pdata;
1033 if (p == nullptr)
1034 return NPERR_GENERIC_ERROR;
1036 switch (variable)
1038 case NPPVpluginNameString: *((const char**) value) = JuceBrowserPlugin_Name; break;
1039 case NPPVpluginDescriptionString: *((const char**) value) = JuceBrowserPlugin_Desc; break;
1040 case NPPVpluginScriptableNPObject: *((NPObject**) value) = p->getScriptableObject(); break;
1041 default: return NPERR_GENERIC_ERROR;
1044 return NPERR_NO_ERROR;
1047 NPError NPP_NewStream (NPP npp, NPMIMEType type, NPStream* stream, NPBool seekable, ::uint16* stype)
1049 if (npp == nullptr)
1050 return NPERR_INVALID_INSTANCE_ERROR;
1052 return NPERR_NO_ERROR;
1055 ::int32 NPP_WriteReady (NPP npp, NPStream *stream)
1057 if (npp == nullptr)
1058 return NPERR_INVALID_INSTANCE_ERROR;
1060 return 0x0fffffff;
1063 ::int32 NPP_Write (NPP npp, NPStream *stream, ::int32 offset, ::int32 len, void *buffer)
1065 if (npp == nullptr)
1066 return NPERR_INVALID_INSTANCE_ERROR;
1068 return len;
1071 NPError NPP_DestroyStream (NPP npp, NPStream *stream, NPError reason)
1073 if (npp == nullptr)
1074 return NPERR_INVALID_INSTANCE_ERROR;
1076 return NPERR_NO_ERROR;
1079 void NPP_StreamAsFile (NPP npp, NPStream* stream, const char* fname)
1081 if (npp == nullptr)
1082 return;
1085 void NPP_Print (NPP npp, NPPrint* printInfo)
1087 if (npp == nullptr)
1088 return;
1091 void NPP_URLNotify (NPP npp, const char* url, NPReason reason, void* notifyData)
1093 if (npp == nullptr)
1094 return;
1097 NPError NPP_SetValue (NPP npp, NPNVariable variable, void* value)
1099 if (npp == nullptr)
1100 return NPERR_INVALID_INSTANCE_ERROR;
1102 return NPERR_NO_ERROR;
1105 ::int16 NPP_HandleEvent (NPP npp, void* ev)
1107 if (npp != nullptr)
1109 //JucePluginInstance* const p = (JucePluginInstance*) npp->pdata;
1112 return 0;
1116 //==============================================================================
1117 static NPP getInstance (const BrowserPluginComponent* bpc)
1119 BrowserPluginHolderComponent* holder = dynamic_cast <BrowserPluginHolderComponent*> (bpc->getParentComponent());
1121 if (holder != nullptr)
1122 return holder->npp;
1124 return currentlyInitialisingNPP;
1127 //==============================================================================
1128 BrowserPluginComponent::BrowserPluginComponent()
1132 BrowserPluginComponent::~BrowserPluginComponent()
1136 const String BrowserPluginComponent::getBrowserVersion() const
1138 if (browserVersionDesc.isEmpty())
1140 if (getInstance (this) != nullptr)
1141 browserVersionDesc << browser.uagent (getInstance (this));
1142 else
1143 browserVersionDesc << "Netscape Plugin V" << (int) ((browser.version >> 8) & 0xff)
1144 << "." << (int) (browser.version & 0xff);
1147 return browserVersionDesc;
1150 //==============================================================================
1151 #if JUCE_WINDOWS
1152 extern const String getActiveXBrowserURL (const BrowserPluginComponent* comp);
1153 #endif
1155 const String BrowserPluginComponent::getBrowserURL() const
1157 String result;
1159 #if JUCE_WINDOWS
1160 result = getActiveXBrowserURL (this);
1162 if (result.isNotEmpty())
1163 return result;
1164 #endif
1166 // (FireFox doesn't seem happy if you call this from a background thread..)
1167 jassert (MessageManager::getInstance()->isThisTheMessageThread());
1169 NPP npp = getInstance (this);
1170 if (npp != nullptr)
1172 NPObject* windowObj = nullptr;
1173 browser.getvalue (npp, NPNVWindowNPObject, &windowObj);
1175 if (windowObj != nullptr)
1177 NPVariant location;
1178 bool ok = browser.getproperty (npp, windowObj,
1179 browser.getstringidentifier ("location"), &location);
1180 browser.releaseobject (windowObj);
1182 jassert (ok);
1183 if (ok)
1185 NPVariant href;
1186 ok = browser.getproperty (npp, location.value.objectValue,
1187 browser.getstringidentifier ("href"), &href);
1188 browser.releasevariantvalue (&location);
1190 jassert (ok);
1191 if (ok)
1193 result = URL::removeEscapeChars (createValueFromNPVariant (npp, href).toString());
1194 browser.releasevariantvalue (&href);
1200 return result;